/*
 * Copyright 2025 the original author or authors.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * https://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.openrewrite.maven;

import org.junit.jupiter.api.Test;
import org.openrewrite.DocumentExample;
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;

import static org.openrewrite.java.Assertions.mavenProject;
import static org.openrewrite.maven.Assertions.pomXml;

class RemoveRedundantPropertiesTest implements RewriteTest {

    @Override
    public void defaults(RecipeSpec spec) {
        spec.recipe(new RemoveRedundantProperties(null, null));
    }

    @DocumentExample
    @Test
    void removeRedundantPropertyFromChild() {
        rewriteRun(
          mavenProject("parent",
            pomXml(
              """
                <project>
                  <groupId>com.example</groupId>
                  <artifactId>parent</artifactId>
                  <version>1.0.0</version>
                  <packaging>pom</packaging>
                  <properties>
                    <junit.version>5.9.1</junit.version>
                    <spring.version>6.0.0</spring.version>
                  </properties>
                  <modules>
                    <module>child</module>
                  </modules>
                </project>
                """
            ),
            mavenProject("child",
              pomXml(
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                    <properties>
                      <junit.version>5.9.1</junit.version>
                      <custom.property>value</custom.property>
                    </properties>
                  </project>
                  """,
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                    <properties>
                      <custom.property>value</custom.property>
                    </properties>
                  </project>
                  """
              )
            )
          )
        );
    }

    @Test
    void removeMultipleRedundantProperties() {
        rewriteRun(
          mavenProject("parent",
            pomXml(
              """
                <project>
                  <groupId>com.example</groupId>
                  <artifactId>parent</artifactId>
                  <version>1.0.0</version>
                  <packaging>pom</packaging>
                  <properties>
                    <junit.version>5.9.1</junit.version>
                    <spring.version>6.0.0</spring.version>
                    <slf4j.version>2.0.7</slf4j.version>
                  </properties>
                  <modules>
                    <module>child</module>
                  </modules>
                </project>
                """
            ),
            mavenProject("child",
              pomXml(
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                    <properties>
                      <junit.version>5.9.1</junit.version>
                      <spring.version>6.0.0</spring.version>
                      <slf4j.version>2.0.7</slf4j.version>
                    </properties>
                  </project>
                  """,
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                  </project>
                  """
              )
            )
          )
        );
    }

    @Test
    void doNotRemoveNonRedundantProperty() {
        rewriteRun(
          mavenProject("parent",
            pomXml(
              """
                <project>
                  <groupId>com.example</groupId>
                  <artifactId>parent</artifactId>
                  <version>1.0.0</version>
                  <packaging>pom</packaging>
                  <properties>
                    <junit.version>5.9.1</junit.version>
                  </properties>
                  <modules>
                    <module>child</module>
                  </modules>
                </project>
                """
            ),
            mavenProject("child",
              pomXml(
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                    <properties>
                      <custom.property>value</custom.property>
                    </properties>
                  </project>
                  """
              )
            )
          )
        );
    }

    @Test
    void onlyRemoveIfValuesMatchEnabled() {
        rewriteRun(
          spec -> spec.recipe(new RemoveRedundantProperties(null, true)),
          mavenProject("parent",
            pomXml(
              """
                <project>
                  <groupId>com.example</groupId>
                  <artifactId>parent</artifactId>
                  <version>1.0.0</version>
                  <packaging>pom</packaging>
                  <properties>
                    <junit.version>5.9.1</junit.version>
                    <spring.version>6.0.0</spring.version>
                  </properties>
                  <modules>
                    <module>child</module>
                  </modules>
                </project>
                """
            ),
            mavenProject("child",
              pomXml(
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                    <properties>
                      <junit.version>5.9.1</junit.version>
                      <spring.version>5.3.0</spring.version>
                    </properties>
                  </project>
                  """,
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                    <properties>
                      <spring.version>5.3.0</spring.version>
                    </properties>
                  </project>
                  """
              )
            )
          )
        );
    }

    @Test
    void removeWithNamePattern() {
        rewriteRun(
          spec -> spec.recipe(new RemoveRedundantProperties("*.version", null)),
          mavenProject("parent",
            pomXml(
              """
                <project>
                  <groupId>com.example</groupId>
                  <artifactId>parent</artifactId>
                  <version>1.0.0</version>
                  <packaging>pom</packaging>
                  <properties>
                    <junit.version>5.9.1</junit.version>
                    <base.dir>/tmp</base.dir>
                  </properties>
                  <modules>
                    <module>child</module>
                  </modules>
                </project>
                """
            ),
            mavenProject("child",
              pomXml(
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                    <properties>
                      <junit.version>5.9.1</junit.version>
                      <base.dir>/tmp</base.dir>
                    </properties>
                  </project>
                  """,
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                    <properties>
                      <base.dir>/tmp</base.dir>
                    </properties>
                  </project>
                  """
              )
            )
          )
        );
    }

    @Test
    void removeFromGrandchild() {
        rewriteRun(
          mavenProject("parent",
            pomXml(
              """
                <project>
                  <groupId>com.example</groupId>
                  <artifactId>parent</artifactId>
                  <version>1.0.0</version>
                  <packaging>pom</packaging>
                  <properties>
                    <junit.version>5.9.1</junit.version>
                  </properties>
                  <modules>
                    <module>child</module>
                  </modules>
                </project>
                """
            ),
            mavenProject("child",
              pomXml(
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                    <packaging>pom</packaging>
                    <modules>
                      <module>grandchild</module>
                    </modules>
                  </project>
                  """
              ),
              mavenProject("grandchild",
                pomXml(
                  """
                    <project>
                      <parent>
                        <groupId>com.example</groupId>
                        <artifactId>child</artifactId>
                        <version>1.0.0</version>
                      </parent>
                    
                      <artifactId>grandchild</artifactId>
                    
                      <properties>
                        <junit.version>5.9.1</junit.version>
                      </properties>
                    </project>
                    """,
                  """
                    <project>
                      <parent>
                        <groupId>com.example</groupId>
                        <artifactId>child</artifactId>
                        <version>1.0.0</version>
                      </parent>
                    
                      <artifactId>grandchild</artifactId>
                    </project>
                    """
                )
              )
            )
          )
        );
    }

    @Test
    void preservePropertyWithComments() {
        rewriteRun(
          mavenProject("parent",
            pomXml(
              """
                <project>
                  <groupId>com.example</groupId>
                  <artifactId>parent</artifactId>
                  <version>1.0.0</version>
                  <packaging>pom</packaging>
                  <properties>
                    <junit.version>5.9.1</junit.version>
                  </properties>
                  <modules>
                    <module>child</module>
                  </modules>
                </project>
                """
            ),
            mavenProject("child",
              pomXml(
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                    <properties>
                      <!-- This property is intentionally overridden -->
                      <junit.version>5.9.1</junit.version>
                      <custom.property>value</custom.property>
                    </properties>
                  </project>
                  """,
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                    <properties>
                      <custom.property>value</custom.property>
                    </properties>
                  </project>
                  """
              )
            )
          )
        );
    }

    @Test
    void removePropertyWithExpressionValue() {
        rewriteRun(
          spec -> spec.recipe(new RemoveRedundantProperties(null, true)),
          mavenProject("parent",
            pomXml(
              """
                <project>
                  <groupId>com.example</groupId>
                  <artifactId>parent</artifactId>
                  <version>1.0.0</version>
                  <packaging>pom</packaging>
                  <properties>
                    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                    <maven.compiler.source>17</maven.compiler.source>
                  </properties>
                  <modules>
                    <module>child</module>
                  </modules>
                </project>
                """
            ),
            mavenProject("child",
              pomXml(
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                    <properties>
                      <project.build.sourceEncoding>${project.build.sourceEncoding}</project.build.sourceEncoding>
                      <maven.compiler.source>17</maven.compiler.source>
                    </properties>
                  </project>
                  """,
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                    <properties>
                      <project.build.sourceEncoding>${project.build.sourceEncoding}</project.build.sourceEncoding>
                    </properties>
                  </project>
                  """
              )
            )
          )
        );
    }

    @Test
    void handleNoParentPom() {
        rewriteRun(
          pomXml(
            """
              <project>
                <groupId>com.example</groupId>
                <artifactId>standalone</artifactId>
                <version>1.0.0</version>
                <properties>
                  <junit.version>5.9.1</junit.version>
                </properties>
              </project>
              """
          )
        );
    }

    @Test
    void removePropertyWhenAllPropertiesRemoved() {
        rewriteRun(
          mavenProject("parent",
            pomXml(
              """
                <project>
                  <groupId>com.example</groupId>
                  <artifactId>parent</artifactId>
                  <version>1.0.0</version>
                  <packaging>pom</packaging>
                  <properties>
                    <junit.version>5.9.1</junit.version>
                  </properties>
                  <modules>
                    <module>child</module>
                  </modules>
                </project>
                """
            ),
            mavenProject("child",
              pomXml(
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                    <properties>
                      <junit.version>5.9.1</junit.version>
                    </properties>
                  </project>
                  """,
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                  </project>
                  """
              )
            )
          )
        );
    }

    @Test
    void removePropertyFromRelativePathParent() {
        rewriteRun(
          mavenProject("parent-folder",
            pomXml(
              """
                <project>
                  <groupId>com.example</groupId>
                  <artifactId>parent</artifactId>
                  <version>1.0.0</version>
                  <packaging>pom</packaging>
                  <properties>
                    <spring.version>6.0.0</spring.version>
                  </properties>
                </project>
                """
            )
          ),
          mavenProject("child-folder",
            pomXml(
              """
                <project>
                  <parent>
                    <groupId>com.example</groupId>
                    <artifactId>parent</artifactId>
                    <version>1.0.0</version>
                    <relativePath>../parent-folder/pom.xml</relativePath>
                  </parent>
                  <artifactId>child</artifactId>
                  <properties>
                    <spring.version>6.0.0</spring.version>
                  </properties>
                </project>
                """,
              """
                <project>
                  <parent>
                    <groupId>com.example</groupId>
                    <artifactId>parent</artifactId>
                    <version>1.0.0</version>
                    <relativePath>../parent-folder/pom.xml</relativePath>
                  </parent>
                  <artifactId>child</artifactId>
                </project>
                """
            )
          )
        );
    }

    @Test
    void preserveEmptyPropertyTag() {
        rewriteRun(
          mavenProject("parent",
            pomXml(
              """
                <project>
                  <groupId>com.example</groupId>
                  <artifactId>parent</artifactId>
                  <version>1.0.0</version>
                  <packaging>pom</packaging>
                  <properties>
                    <empty.property></empty.property>
                  </properties>
                  <modules>
                    <module>child</module>
                  </modules>
                </project>
                """
            ),
            mavenProject("child",
              pomXml(
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                    <properties>
                      <empty.property></empty.property>
                    </properties>
                  </project>
                  """,
                """
                  <project>
                    <parent>
                      <groupId>com.example</groupId>
                      <artifactId>parent</artifactId>
                      <version>1.0.0</version>
                    </parent>
                    <artifactId>child</artifactId>
                  </project>
                  """
              )
            )
          )
        );
    }

    @Test
    void externalSpringBootDependenciesParent() {
        rewriteRun(
          pomXml(
            """
              <project>
                <parent>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-dependencies</artifactId>
                  <version>3.5.4</version>
                  <relativePath/>
                </parent>
                <artifactId>child</artifactId>
                <properties>
                  <junit.version>4.13.2</junit.version>
                  <custom.property>value</custom.property>
                </properties>
              </project>
              """,
            """
              <project>
                <parent>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-dependencies</artifactId>
                  <version>3.5.4</version>
                  <relativePath/>
                </parent>
                <artifactId>child</artifactId>
                <properties>
                  <custom.property>value</custom.property>
                </properties>
              </project>
              """
          )
        );
    }

    @Test
    void externalSpringBootStarterParent() {
        rewriteRun(
          pomXml(
            """
              <project>
                <parent>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-parent</artifactId>
                  <version>3.5.4</version>
                  <relativePath/>
                </parent>
                <artifactId>child</artifactId>
                <properties>
                  <junit.version>4.13.2</junit.version>
                  <custom.property>value</custom.property>
                </properties>
              </project>
              """,
            """
              <project>
                <parent>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-parent</artifactId>
                  <version>3.5.4</version>
                  <relativePath/>
                </parent>
                <artifactId>child</artifactId>
                <properties>
                  <custom.property>value</custom.property>
                </properties>
              </project>
              """
          )
        );
    }
}
